package com.power.sifa.net.service.impl;

import com.alibaba.fastjson.JSON;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.plf.common.exception.BusinessException;
import com.plf.common.utils.SpringHolder;
import com.plf.common.utils.StringUtil;
import com.plf.core.base.service.Ha_entityormService;
import com.power.sifa.net.dao.Apl_formDao;
import com.power.sifa.net.model.General_tree;
import com.power.sifa.net.model.General_tree_option;
import com.power.sifa.net.model.General_tree_sub;
import com.power.sifa.net.service.General_treeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class General_treeServiceImpl implements General_treeService {

    @Resource
    private Apl_formDao apl_formDao;

    // @Resource
    // private Apl_attach_append_listService apl_attach_append_listService;

    @Resource
    private Ha_entityormService ha_entityormService;

    @Override
    public List<Map<String, Object>> addBuild(String applyid, String cornumber, List<General_tree> treeBuildList) throws Exception {
        // 递归配置树数据
        for (General_tree g : treeBuildList) {
            // ^ 只初始化顶级节点, 企业表靠"cornumber"关联的。 其它都是子节点靠其它字段进行关联, 后续会递归初始化
            if("cornumber".equals(g.getEntrelationfield())) {
                this.addRecursionBuildTree(applyid, g, new ArrayList<String>() {{
                    add(cornumber);
                }}, null);
            }
        }
        List<Map<String, Object>> result = new ArrayList<>(10);

        // 递归取出树数据
        this.recursionValue(result, treeBuildList, 1);
        return result;
    }

    @Override
    public List<Map<String, Object>> editBuild(String applyid, List<General_tree> treeBuildList) throws BusinessException {
        // 递归查询树数据
        for (General_tree g : treeBuildList) {
            this.editRecursionBuildTree(g, new ArrayList<String>() {{
                add(applyid);
            }}, null);
        }
        List<Map<String, Object>> result = new ArrayList<>(10);
        // 递归取出树数据
        this.recursionValue(result, treeBuildList, 1);
        return result;
    }

    // 递归组装数据
    private void recursionValue(List<Map<String, Object>> result, List<General_tree> treeBuildList, Integer index) {
        // log.info("第{}次递归", index);
        for (General_tree treeBuild : treeBuildList) {
            if (!CollectionUtils.isEmpty(treeBuild.getData())) {
                // 循环本节点数据
                for (Map<String, Object> data : treeBuild.getData()) {
                    data.put("apltable", treeBuild.getApltable());
                    List<Map<String, Object>> childrenList = new ArrayList<>();
                    // 循环子节点
                    if (!CollectionUtils.isEmpty(treeBuild.getChildren())) {
                        for (General_tree child : treeBuild.getChildren()) {
                            // 循环子节点数据
                            if (!CollectionUtils.isEmpty(child.getData())) {
                                for (Map<String, Object> sdata : child.getData()) {
                                    if (data.get("id").equals(sdata.get("parentid"))) {
                                        // sdata.put("children", sdata.get("tablist"));
                                        childrenList.add(sdata);
                                    }
                                }
                            }
                        }
                    }
                    data.put("children", childrenList);
                    result.add(data);
                }
            }
            if (!CollectionUtils.isEmpty(treeBuild.getChildren())) {
                this.recursionValue(new ArrayList<>(), treeBuild.getChildren(), index);
            }

        }

    }

    @Override
    public void delNode(String applyid, String id, General_tree_option treeOption) {
        List<String> ids = new ArrayList<String>(1) {{
            add(id);
        }};
        this.ha_entityormService.removeByFields(treeOption.getApltable(), "id", ids);

        // 如果需要同步补正, 调一下接口
//        if (treeOption.getIsappend()) {
//            this.apl_attach_append_listService.syncAppend(applyid, treeOption.getApltable(), id);
//        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveNode(String applyid, General_tree_option treeOption) throws Exception {
        treeOption.getConfig();
        String id = (String) treeOption.getData().get("id");
        List<String> ids = new ArrayList<String>(1) {{
            add(id);
        }};
        // 先删除, 后保存
        this.ha_entityormService.removeByFields(treeOption.getApltable(), "id", ids);
        this.ha_entityormService.saveObject(SpringHolder.getBean(treeOption.getApltable()).getClass(), id, treeOption.getData());
        if (treeOption.getData().get("tablemap") != null) {
            Map<String, Object> tableMap = (Map<String, Object>) treeOption.getData().get("tablemap");
            for (Map.Entry<String, Object> entry : tableMap.entrySet()) {
                if(null == treeOption.getConfig().get(entry.getKey())) {
                    throw new BusinessException("saveNode 从表关联配置为空");
                }
                Map<String, Object> configMap = (Map<String, Object>) treeOption.getConfig().get(entry.getKey());
                List<Map<String, Object>> subList = (List<Map<String, Object>>) entry.getValue();
                // 先删除从表数据
                this.ha_entityormService.removeByFields(entry.getKey(), (String) configMap.get("relationfield"), ids);
                // 删除完进行保存
                this.aplSaveAll(entry.getKey(), subList);
            }
        }
        // 如果需要同步补正, 调一下接口
//        if (treeOption.getIsappend()) {
//            this.apl_attach_append_listService.syncAppend(applyid, treeOption.getApltable(), id);
//        }

    }

    /**
     * 递归构建树数据
     *
     * @param applyid
     * @param treeBuild
     * @param faids
     * @param faNanoMap
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private void addRecursionBuildTree(String applyid, General_tree treeBuild, List<String> faids, Map<String, String> faNanoMap) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, BusinessException {
        // 1. 查出企业库数据(主从表), 转申请表
        Map<String, Object> resultMap = this.getAddAplList(applyid, treeBuild, faids, faNanoMap);
        if (resultMap == null) {
            log.info("{}主表表无数据", treeBuild.getApltable());
            return;
        }
        List<Map<String, Object>> aplList = (List<Map<String, Object>>) resultMap.get("list");
        List<String> myids = (List<String>) resultMap.get("myids");
        Map<String, String> NanoMap = (Map<String, String>) resultMap.get("NanoMap");
        // 2. 处理从表数据
        if (!CollectionUtils.isEmpty(treeBuild.getSublist())) {
            this.getAddSubList(applyid, treeBuild.getSublist(), myids, NanoMap, aplList);
        }
        // 2. 存在多从表, 根据表名转化成一个map
        for (Map<String, Object> aplObj : aplList) {
            if (null != aplObj.get("tablelist")) {
                {
                    List<Map<String, Object>> tableList = (List<Map<String, Object>>) aplObj.get("tablelist");
                    Map<String, List<Map<String, Object>>> tabMap = new HashMap<>(16);
                    List<Map<String, Object>> tempList;
                    for (Map<String, Object> t : tableList) {
                        if (null != tabMap.get(t.get("apltable"))) {
                            tempList = tabMap.get(t.get("apltable"));
                        } else {
                            tempList = new ArrayList<>();
                        }
                        tempList.add(t);
                        tabMap.put((String) t.get("apltable"), tempList);
                    }
                    aplObj.put("tablemap", tabMap);
                }
            }
        }
        // 3. 存入主表数据
        treeBuild.setData(aplList);
        // 4. 还有子节点继续递归
        if (!CollectionUtils.isEmpty(treeBuild.getChildren())) {
            for (General_tree c : treeBuild.getChildren()) {
                this.addRecursionBuildTree(applyid, c, myids, NanoMap);
            }
        }
    }

    /**
     * 处理从表数据
     *
     * @param applyid
     * @param sublist
     * @param faids
     * @param faNanoMap
     * @param faAplList
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private void getAddSubList(String applyid, List<General_tree_sub> sublist, List<String> faids, Map<String, String> faNanoMap, List<Map<String, Object>> faAplList) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, BusinessException {
        List<Map<String, Object>> subEntList;
        Map<String, Object> aplObj;
        List<Map<String, Object>> aplList;
        for (General_tree_sub s : sublist) {
            subEntList = this.apl_formDao.queryBatchList(s.getEnttable(), s.getRelationfield(), faids);
            aplList = new ArrayList<>();
            for (Map<String, Object> sentObj : subEntList) {
                aplObj = new HashMap<>(16);
                if (sentObj.get(s.getRelationfield()) != null && faNanoMap.get(sentObj.get(s.getRelationfield()).toString()) != null) {
                    // 1. 更新父级的关联字段
                    aplObj.put(s.getRelationfield(), faNanoMap.get(sentObj.get(s.getRelationfield()).toString()));
                } else {
                    log.info("原始从表父级关联id缺失 -> {}", JSON.toJSONString(sentObj));
                    throw new BusinessException("原始从表父级关联id缺失");
                }
                // 2. 更新id
                aplObj.put("srcid", sentObj.get("id").toString());
                aplObj.put("id", applyid + NanoIdUtils.randomNanoId());
                aplObj.put("applyid", applyid);
                aplObj.put("apltable", s.getApltable());
                // 3. 根据映射关系转成申请表对象列表
                for (Map.Entry<String, String> entry : s.getMaprelation().entrySet()) {
                    if (sentObj.get(entry.getKey()) != null) {
                        aplObj.put(entry.getValue(), sentObj.get(entry.getKey()));
                    }
                }
                // 从表当属性放进主表里去
                for (Map<String, Object> faApl : faAplList) {
                    // 根据从表新关联的父级id匹配
                    if (faApl.get("id").equals(faNanoMap.get(sentObj.get(s.getRelationfield()).toString()))) {
                        List<Map<String, Object>> tableList;
                        if (faApl.get("tablelist") != null) {
                            tableList = (List<Map<String, Object>>) faApl.get("tablelist");
                        } else {
                            tableList = new ArrayList<>(10);
                        }
                        tableList.add(aplObj);
                        faApl.put("tablelist", tableList);
                        break;
                    }
                }
                aplList.add(aplObj);
            }
            // 4. 保存装换数据
            this.aplSaveAll(s.getApltable(), aplList);
        }
    }

    /**
     * 查询企业表转换成申请表并保存返回
     *
     * @param applyid
     * @param treeBuild
     * @param faids
     * @return
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private Map<String, Object> getAddAplList(String applyid, General_tree treeBuild, List<String> faids, Map<String, String> faNanoMap) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, BusinessException {
        // 顶级节点是根据cornumber(如已配置用配置的)进行关联的, 下级节点根据配置的关联字段进行关联
        List<Map<String, Object>> entList = this.apl_formDao.queryBatchList(treeBuild.getEnttable(), treeBuild.getEntrelationfield(), faids);

        if (CollectionUtils.isEmpty(entList)) {
            return null;
        }
        // 1.3 主表的NanoId生成后, 更新从表的引用
        List<String> myids = new ArrayList<>(entList.size());
        // 中转map, 记录新旧id的变化
        Map<String, String> NanoMap = new HashMap<>(16);

        List<Map<String, Object>> aplList = new ArrayList<>();
        Map<String, Object> aplObj;
        for (Map<String, Object> e : entList) {
            aplObj = new HashMap<>(16);
            // 1.0 转换主表关联id
            if (treeBuild.getToplevel()) {
                // 根节点给0
                aplObj.put("parentid", 0);
            } else {
                // 从表从父级转换的map取
                String relationfield = treeBuild.getRelationfield().equals("applyid") ? "cornumber" : treeBuild.getRelationfield();
                if (faNanoMap.get(e.get(relationfield).toString()) != null) {
                    aplObj.put("parentid", faNanoMap.get(e.get(relationfield).toString()));
                    aplObj.put(treeBuild.getRelationfield(), faNanoMap.get(e.get(relationfield).toString()));
                } else {
                    log.info("原始主表父级关联id缺失 -> {}", JSON.toJSONString(e));
                    throw new BusinessException("原始主表父级关联id缺失");
                }
            }
            // 1.1 备份一下myids, 为下次递归的faids
            String oldid = e.get("id").toString();
            myids.add(oldid);
            // 更新srcid(srcid=自身的id), applyid = applyid
            aplObj.put("srcid", oldid);
            aplObj.put("applyid", applyid);
            // 1.2 主从表的id重新生产成NanoId (顶级关联的是applyid, 其他的节点可随机)
            String newid = applyid + NanoIdUtils.randomNanoId();
            // 1.3 记录新旧id的变化
            NanoMap.put(oldid, newid);
            // 1.4 更新企业表id
            aplObj.put("id", newid);
            // 2. 根据映射关系转成申请表对象列表
            for (Map.Entry<String, String> entry : treeBuild.getMaprelation().entrySet()) {
                if (e.get(entry.getKey()) != null) {
                    aplObj.put(entry.getValue(), e.get(entry.getKey()));
                }
            }
            // 前端组件作用域插槽固定写法
            aplObj.put("scopedSlots", new HashMap<String, String>() {{
                put("title", "title");
            }});
            // 树组件右侧显示的主字段(如果没有配置显示字段, 又是根节点 name = 生产场地)
            if (StringUtil.isEmpty(treeBuild.getPrimary()) && treeBuild.getToplevel()) {
                aplObj.put("name", treeBuild.getLabel());
            } else {
                aplObj.put("name", aplObj.get(treeBuild.getPrimary()));
            }
            aplList.add(aplObj);
        }
        // 2.1 保存申请主表
        this.aplSaveAll(treeBuild.getApltable(), aplList);
        Map<String, Object> resultMap = new HashMap<>(16);
        // 3. 根据过滤条件筛选一遍 todo用到再加
        resultMap.put("list", aplList);
        resultMap.put("myids", myids);
        resultMap.put("NanoMap", NanoMap);
        return resultMap;
    }

    /**
     * 反射保存申请表数据
     *
     * @param apltable
     * @param aplList
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private void aplSaveAll(String apltable, List<Map<String, Object>> aplList) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class cla = SpringHolder.getBean(apltable).getClass();
        List templist = JSON.parseArray(JSON.toJSONString(aplList), cla);
        // 2. 调用saveAll方法
        Object objService = SpringHolder.getBean(apltable + "ServiceImpl");
        Method method = objService.getClass().getDeclaredMethod("saveAll", List.class);
        method.invoke(objService, templist);
    }

    /**
     * 编辑获取申请表列表
     *
     * @param treeBuild
     * @param faids
     * @param faNanoMap
     * @return
     */
    private Map<String, Object> getEditAplList(General_tree treeBuild, List<String> faids, Map<String, String> faNanoMap) throws BusinessException {

        // 根据关联字段查询
        List<Map<String, Object>> aplList = this.apl_formDao.queryBatchList(treeBuild.getApltable(), treeBuild.getRelationfield(), faids);

        if (CollectionUtils.isEmpty(aplList)) {
            return null;
        }
        List<String> myids = new ArrayList<>(aplList.size());
        Map<String, String> NanoMap = new HashMap<>(16);
        for (Map<String, Object> aplObj : aplList) {
            // 1.0 转换主表关联id
            if (treeBuild.getToplevel()) {
                // 根节点给0
                aplObj.put("parentid", 0);
            } else {
                // 从表从父级转换的map取
                if (faNanoMap.get(aplObj.get(treeBuild.getRelationfield())) != null) {
                    aplObj.put("parentid", faNanoMap.get(aplObj.get(treeBuild.getRelationfield())));
                } else {
                    log.info("原始主表父级关联id缺失 -> {}", JSON.toJSONString(aplObj));
                    throw new BusinessException("原始主表父级关联id缺失");
                }
            }
            myids.add((String) aplObj.get("id"));
            NanoMap.put((String) aplObj.get("id"), (String) aplObj.get("id"));
            // 前端组件作用域插槽固定写法
            aplObj.put("scopedSlots", new HashMap<String, String>() {{
                put("title", "title");
            }});
            // 树组件右侧显示的主字段
            // 树组件右侧显示的主字段(如果没有配置显示字段, 又是根节点 name = 生产场地)
            if (StringUtil.isEmpty(treeBuild.getPrimary()) && treeBuild.getToplevel()) {
                aplObj.put("name", treeBuild.getLabel());
            } else {
                aplObj.put("name", aplObj.get(treeBuild.getPrimary()));
            }
        }
        Map<String, Object> resultMap = new HashMap<>(16);
        // 3. 根据过滤条件筛选一遍 todo用到再加
        resultMap.put("list", aplList);
        resultMap.put("myids", myids);
        resultMap.put("NanoMap", NanoMap);
        return resultMap;
    }

    /**
     * 编辑构建树
     *
     * @param treeBuild
     * @param faids
     * @param faNanoMap
     */
    private void editRecursionBuildTree(General_tree treeBuild, List<String> faids, Map<String, String> faNanoMap) throws BusinessException {
        // 1. 查出申请表
        Map<String, Object> resultMap = this.getEditAplList(treeBuild, faids, faNanoMap);
        if (resultMap == null) {
            log.info("{}主表表无数据", treeBuild.getApltable());
            return;
        }
        List<Map<String, Object>> aplList = (List<Map<String, Object>>) resultMap.get("list");
        List<String> myids = (List<String>) resultMap.get("myids");
        Map<String, String> NanoMap = (Map<String, String>) resultMap.get("NanoMap");
        // 2. 处理从表数据
        if (!CollectionUtils.isEmpty(treeBuild.getSublist())) {
            this.getEditSubList(treeBuild.getSublist(), myids, NanoMap, aplList);
        }
        // 2. 存在多从表, 根据表名转化成一个map
        for (Map<String, Object> aplObj : aplList) {
            if (null != aplObj.get("tablelist")) {
                {
                    List<Map<String, Object>> tableList = (List<Map<String, Object>>) aplObj.get("tablelist");
                    Map<String, List<Map<String, Object>>> tabMap = new HashMap<>(16);
                    List<Map<String, Object>> tempList;
                    for (Map<String, Object> t : tableList) {
                        if (null != tabMap.get(t.get("apltable"))) {
                            tempList = tabMap.get(t.get("apltable"));
                        } else {
                            tempList = new ArrayList<>();
                        }
                        tempList.add(t);
                        tabMap.put((String) t.get("apltable"), tempList);
                    }
                    aplObj.put("tablemap", tabMap);
                }
            }
        }
        // 3. 存入主表数据
        treeBuild.setData(aplList);
        // 4. 还有子节点继续递归
        if (!CollectionUtils.isEmpty(treeBuild.getChildren())) {
            for (General_tree c : treeBuild.getChildren()) {
                this.editRecursionBuildTree(c, myids, NanoMap);
            }
        }
    }

    ;

    /**
     * 编辑处理从表数据
     *
     * @param sublist
     * @param faids
     * @param faNanoMap
     * @param faAplList
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private void getEditSubList(List<General_tree_sub> sublist, List<String> faids, Map<String, String> faNanoMap, List<Map<String, Object>> faAplList) {
        List<Map<String, Object>> subAplList;
        for (General_tree_sub s : sublist) {
            subAplList = this.apl_formDao.queryBatchList(s.getApltable(), s.getRelationfield(), faids);
            for (Map<String, Object> sentObj : subAplList) {
                // 从表当属性放进主表里去
                for (Map<String, Object> faApl : faAplList) {
                    // 根据从表新关联的父级id匹配
                    sentObj.put("apltable", s.getApltable());
                    if (faApl.get("id").equals(faNanoMap.get(sentObj.get(s.getRelationfield()).toString()))) {
                        List<Map<String, Object>> tableList;
                        if (faApl.get("tablelist") != null) {
                            tableList = (List<Map<String, Object>>) faApl.get("tablelist");
                        } else {
                            tableList = new ArrayList<>(10);
                        }
                        tableList.add(sentObj);
                        faApl.put("tablelist", tableList);
                        break;
                    }
                }
            }
        }
    }

}
